/*
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package botobjects;

import interfaces.BotObject;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import main.CommonMethods;

import org.apache.log4j.Logger;
import org.jibble.pircbot.Colors;

import tools.StringTools;
import tools.UtopiaTime;
import database.DBConnectionFactory;

/**
 * A class representing an attack
 * 
 * 
 */
public class Attack implements BotObject {
   /**
    * Returns an attack
    * 
    * @param searchFor
    *           used to decide which attack to return
    * @return an Attack object. Returns null if no object was found
    */
   public static Attack getAttack(final String searchFor) {
	  if (searchFor == null)
		 return null;
	  Attack out = null;
	  PreparedStatement ps = null;
	  ResultSet srs = null;
	  ResultSet rs = null;
	  try {
		 if ("".equals(searchFor)) {
			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("SELECT * FROM attacks ORDER BY timeofhit DESC");
		 } else {
			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("SELECT * FROM attacks WHERE targetprov LIKE ? OR" + " nick = ? ORDER BY timeofhit DESC");
			ps.setString(1, "%" + searchFor + "%");
			ps.setString(2, searchFor);
		 }
		 srs = ps.executeQuery();

		 if (srs.next()) {
			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("SELECT kdloc FROM province WHERE name = ?");
			ps.setString(1, srs.getString("targetprov"));
			rs = ps.executeQuery();

			if (rs.next()) {
			   out = new Attack(srs.getString("nick"), srs.getString("targetprov"), rs.getString("kdloc"), srs.getTimestamp(
					 "timeofhit").getTime(), srs.getString("gains"), srs.getInt("mo"), srs.getString("attacktype"));
			}
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			srs.close();
		 } catch (final Exception e) {
		 }
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   private String attacker = "";
   private String defender = "";
   private String defenderLoc = "";
   private Long timeOfAttack = 0L;
   private String gain = "";
   private Long timeOfReturn = 0L;
   private int mo = 0;

   private String attackType = "";

   public Attack(final String attacker, final String defender, final String defenderLoc, final Long timeOfAttack,
		 final String gain, final int mo, final String attackType) {
	  this.attacker = attacker;
	  this.defender = defender;
	  this.defenderLoc = defenderLoc;
	  this.timeOfAttack = timeOfAttack;
	  this.gain = gain;
	  this.mo = mo;
	  this.attackType = attackType;
   }

   public Attack(final String attacker, final String defender, final String defenderLoc, final Long timeOfAttack,
		 final String gain, final Long timeOfReturn, final int mo, final String attackType) {
	  this.attacker = attacker;
	  this.defender = defender;
	  this.defenderLoc = defenderLoc;
	  this.timeOfAttack = timeOfAttack;
	  this.timeOfReturn = timeOfReturn;
	  this.gain = gain;
	  this.mo = mo;
	  this.attackType = attackType;
   }

   public String getAttacker() {
	  return attacker;
   }

   public String getAttackType() {
	  return attackType;
   }

   public String getDefender() {
	  return defender;
   }

   public String getDefenderLoc() {
	  return defenderLoc;
   }

   public String getGain() {
	  return gain;
   }

   @Override
   public List<String> getIRCOutput(final int outputType, final String... args) {
	  List<String> out = new LinkedList<String>();
	  if (StringTools.isNullOrEmpty(getAttacker()) || StringTools.isNullOrEmpty(getDefender())
			|| StringTools.isNullOrEmpty(getDefenderLoc()) || getTimeOfAttack() == null || getTimeOfReturn() == null
			|| getGain() == null || StringTools.isNullOrEmpty(getAttackType()))
		 return out;
	  UtopiaTime ut = new UtopiaTime(getTimeOfAttack());
	  String timeAgo = UtopiaTime.compareTimes(getTimeOfAttack());
	  out.add(Colors.BLUE + getDefender() + " " + getDefenderLoc() + Colors.OLIVE + " was last hit by " + Colors.RED
			+ getAttacker() + Colors.OLIVE + " on " + Colors.BLUE + ut.formattedUT() + " (" + timeAgo + " ago)");
	  out.add(Colors.RED + getAttackType() + Colors.OLIVE + " with " + Colors.TEAL + getGain() + Colors.OLIVE + ", sending "
			+ Colors.TEAL + getMo() + " offense");
	  return out;
   }

   public int getMo() {
	  return mo;
   }

   @Override
   public Map<String, Object> getRPCOutput(final int... includes) {
	  Map<String, Object> out = new HashMap<String, Object>();
	  if (StringTools.isNullOrEmpty(getAttacker()) || StringTools.isNullOrEmpty(getDefender())
			|| StringTools.isNullOrEmpty(getDefenderLoc()) || getTimeOfAttack() == null || getTimeOfReturn() == null
			|| getGain() == null || StringTools.isNullOrEmpty(getAttackType()))
		 return out;
	  out.put("Attacker", getAttacker());
	  out.put("Defender", getDefender());
	  out.put("Defender KD", getDefenderLoc());
	  out.put("Time of Attack", new Date(getTimeOfAttack()));
	  out.put("Gain", getGain());
	  out.put("Time of Return", new Date(getTimeOfReturn()));
	  out.put("Mod Off", getMo());
	  out.put("Attack Type", getAttackType());
	  return out;
   }

   public Long getTimeOfAttack() {
	  return timeOfAttack;
   }

   public Long getTimeOfReturn() {
	  return timeOfReturn;
   }

   @Override
   public boolean saveToDB() {
	  boolean out = false;
	  if (StringTools.isNullOrEmpty(getAttacker()) || StringTools.isNullOrEmpty(getDefender())
			|| StringTools.isNullOrEmpty(getDefenderLoc()) || getTimeOfAttack() == null || getTimeOfReturn() == null
			|| getGain() == null || StringTools.isNullOrEmpty(getAttackType()))
		 return out;
	  PreparedStatement ps = null;
	  if (!CommonMethods.kdExists(getDefenderLoc())) {
		 if (!CommonMethods.addDefaultKD(getDefenderLoc()))
			return out;
	  }
	  if ("".equals(CommonMethods.provinceExists(getDefender()))) {
		 if (!new Province(getDefender(), getDefenderLoc(), "", "", "", 0, 0).saveToDB())
			return out;
	  }
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("INSERT INTO attacks VALUES(?,?,?,?,?,?,?)");
		 ps.setString(1, getAttacker());
		 ps.setString(2, getDefender());
		 ps.setString(3, getDefenderLoc());
		 ps.setString(4, getAttackType());
		 ps.setString(5, getGain());
		 ps.setTimestamp(6, new Timestamp(getTimeOfAttack()));
		 ps.setInt(7, 0);
		 if (ps.executeUpdate() == 1) {
			out = true;
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   public void setAttackType(final String attackType) {
	  this.attackType = attackType;
   }

   public void setGain(final String gain) {
	  this.gain = gain;
   }

   public void setMo(final int mo) {
	  this.mo = mo;
   }

   public void setTimeOfReturn(final Long timeOfReturn) {
	  this.timeOfReturn = timeOfReturn;
   }
}
